﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using TheGameClient.Processes;
using TheGameClient.Webservices;
using Waaahsabi.Controls.TheGame;

namespace TheGameClient
{
	public partial class FeatureUsenetControl : ISystemFeature
	{
		private readonly PagedCollectionView _postPages;
		private readonly ObservableCollection<ThreadControl> _posts;
		private readonly PagedCollectionView _threadPages;
		private readonly ObservableCollection<ThreadControl> _threads;

		public FeatureUsenetControl()
		{
			InitializeComponent();
			ProcessId = Guid.NewGuid();
			//itmLogItems.ItemsSource = logItems;
			HorizontalAlignment = HorizontalAlignment.Stretch;
			VerticalAlignment = VerticalAlignment.Stretch;
			_threads = new ObservableCollection<ThreadControl>();
			_posts = new ObservableCollection<ThreadControl>();
			_threads.CollectionChanged += Threads_CollectionChanged;
			_posts.CollectionChanged += Posts_CollectionChanged;

			_postPages = new PagedCollectionView(Posts);
			postpager.Source = _postPages;
			itmPosts.ItemsSource = _postPages;

			_threadPages = new PagedCollectionView(Threads);
			pager.Source = _threadPages;
			itmThreads.ItemsSource = _threadPages;
		}

		public ObservableCollection<ThreadControl> Threads
		{
			get { return _threads; }
		}

		public ObservableCollection<ThreadControl> Posts
		{
			get { return _posts; }
		}

		#region ISystemFeature Members

		public ulong InterfaceId
		{
			get { return new Guid("5BEE3EA9-35B1-4262-A4DE-2CCF329D2A81").ToLong(); }
		}

		public Guid ProcessId { get; private set; }

		public string ProcessName
		{
			get { return "World Wide Message Board"; }
		}

		public InterfaceCategory Category
		{
			get { return InterfaceCategory.SystemFeature; }
		}

		public ulong SystemId { get; private set; }

		public void Load(ulong systemId)
		{
			SystemId = systemId;
			App.Client.Usenet_GetThreadsCompleted += ClientUsenetGetThreadsCompleted;
			App.Client.Usenet_GetThreadsAsync(App.InternalSessionId, systemId, App.WorldTime, App.WorldTime.AddDays(-1));
		}

		#endregion

		private void Posts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
		}

		private void Threads_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
		}

		private void ClientUsenetGetThreadsCompleted(object sender, Usenet_GetThreadsCompletedEventArgs e)
		{
			App.Client.Usenet_GetThreadsCompleted -= ClientUsenetGetThreadsCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result != null)
			{
				Threads.Clear();
				foreach (var i in e.Result.OrderByDescending(it => it.TimeStamp))
				{
					ThreadControl tc = new ThreadControl
					{
						PostSubject = i.Subject,
						PostTimeStamp = i.TimeStamp,
						PostBody = i.Body,
						PostFrom = i.From,
						PostId = i.Id,
						PostHasFollowUps = i.HasFollowUps,
						PostRootId = i.RootPostId,
						PostReplyToId = i.ReplyToPostId,
					};
					tc.GetFollowUps += GetThreadPosts; //only root nodes have follow ups
					Threads.Add(tc);
				}
			}
		}

		private void GetThreadPosts(object sender, EventArgs e)
		{
			if (sender is ThreadControl)
			{
				ThreadControl s = sender as ThreadControl;
				ThreadControl ctrl = new ThreadControl
				{
					PostId = s.PostId,
					PostSubject = s.PostSubject,
					PostBody = s.PostBody,
					PostRootId = s.PostRootId,
					PostReplyToId = s.PostReplyToId,
					PostTimeStamp = s.PostTimeStamp,
					PostFrom = s.PostFrom,
					IsMessageExpanded = true,
					PostHasFollowUps = s.PostHasFollowUps
				};
				ctrl.Reply += QuoteMessageClicked;
				Posts.Insert(0, ctrl);
				App.Client.Usenet_GetThreadMessagesCompleted += RefreshPosts;
				App.Client.Usenet_GetThreadMessagesAsync(App.InternalSessionId, SystemId, ((ThreadControl) sender).PostId);
			}
		}

		private void QuoteMessageClicked(object sender, EventArgs e)
		{
			if (sender is ThreadControl)
				CreateReplyPost(sender as ThreadControl, true);
		}

		private void TcSubmitMessage(object sender, EventArgs e)
		{
			if (sender is ThreadControl)
			{
				ThreadControl ctrl = sender as ThreadControl;
				UsenetMessage msg = new UsenetMessage();
				msg.Subject = ctrl.NewSubject;
				msg.Body = ctrl.NewBody;
				msg.RootPostId = ctrl.PostRootId;
				msg.ReplyToPostId = ctrl.PostReplyToId;
				_posts.Remove(ctrl);
				App.Client.Usenet_PostMessageCompleted += ClientUsenetPostMessageCompleted;
				App.Client.Usenet_PostMessageAsync(App.InternalSessionId, SystemId, msg);
			}
		}

		//this one is always called in threadView
		private void ClientUsenetPostMessageCompleted(object sender, Usenet_PostMessageCompletedEventArgs e)
		{
			App.Client.Usenet_PostMessageCompleted -= ClientUsenetPostMessageCompleted;
			btnReply.IsEnabled = true;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			App.Client.Usenet_GetThreadMessagesCompleted += RefreshPosts;
			App.Client.Usenet_GetThreadMessagesAsync(App.InternalSessionId, SystemId, _posts.First().PostId);
		}

		private void RefreshPosts(object sender, Usenet_GetThreadMessagesCompletedEventArgs e)
		{
			App.Client.Usenet_GetThreadMessagesCompleted -= RefreshPosts;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result != null)
			{
				VisualStateManager.GoToState(this, "ThreadView", true);
				ThreadControl ctrl1 = Posts.First();
				ctrl1.EnableQuoteButton();
				Posts.Clear();
				Posts.Add(ctrl1);
				if (e.Result.Count > 0)
				{
					int i = 0;
					foreach (UsenetMessage msg in e.Result.OrderBy(it => it.TimeStamp))
					{
						i++;
						ThreadControl ctrl = new ThreadControl
						{
							PostId = msg.Id,
							PostSubject = msg.Subject,
							PostBody = msg.Body,
							PostRootId = msg.RootPostId,
							PostReplyToId = msg.ReplyToPostId,
							PostFrom = msg.From,
							PostHasFollowUps = msg.HasFollowUps,
							IsMessageExpanded = true,
							PostTimeStamp = msg.TimeStamp,
						};
						ctrl.Reply += QuoteMessageClicked;
						if (i%2 == 1)
							ctrl.IsSelected = true;
						Posts.Add(ctrl);
					}
				}
			}
		}

		private void BtnReplyClick(object sender, RoutedEventArgs e)
		{
			CreateReplyPost(Posts.Last());
		}

		private void CreateReplyPost(ThreadControl repliedTo, bool insertQuote = false)
		{
			ThreadControl reply = new ThreadControl
			{
				PostFrom = repliedTo.PostFrom,
				PostReplyToId = repliedTo.PostId,
				PostRootId = repliedTo.PostRootId == 0 ? repliedTo.PostId : repliedTo.PostRootId,
				NewBody =
					insertQuote
						? string.Format("\n\nQuote ({0} on {1}):\n{2}", repliedTo.PostFrom, repliedTo.PostTimeStamp, repliedTo.PostBody)
						: "",
				NewSubject = string.Format("Re: {0}", repliedTo.PostSubject),
				PostTimeStamp = App.WorldTime,
				IsComposing = true,
			};
			reply.SubmitMessage += TcSubmitMessage;
			reply.ComposingCanceled += ReplyComposingCanceled;
			reply.Rendered += delegate
			{
				scrlPosts.InvalidateScrollInfo();
				scrlPosts.ScrollToVerticalOffset(double.PositiveInfinity);
			};

			reply.IsSelected = !_posts.Last().IsSelected;

			postpager.PageIndex = postpager.PageCount;
			foreach (ThreadControl tc in Posts)
				tc.DisableQuoteButton();

			Posts.Add(reply);
			scrlPosts.InvalidateScrollInfo();
			scrlPosts.ScrollToVerticalOffset(double.MaxValue);
			btnReply.IsEnabled = false;
		}

		private void ReplyComposingCanceled(object sender, EventArgs e)
		{
			Posts.Remove(sender as ThreadControl);
			foreach (var i in Posts)
				i.EnableQuoteButton();
			btnReply.IsEnabled = true;
		}

		private void BtnBackClick(object sender, RoutedEventArgs e)
		{
			_posts.Clear();
			VisualStateManager.GoToState(this, "Overview", true);
		}

		#region thread posting

		private void BtnNewThreadClick(object sender, RoutedEventArgs e)
		{
			ThreadControl tc = new ThreadControl();
			tc.SubmitMessage += SubmitNewThread;
			tc.ComposingCanceled += ThreadComposingCanceled;
			tc.IsComposing = true;
			tc.PostTimeStamp = App.WorldTime;
			Threads.Insert(0, tc);
			btnNewThread.IsEnabled = false;
		}

		private void ThreadComposingCanceled(object sender, EventArgs e)
		{
			Threads.Remove(sender as ThreadControl);
			btnNewThread.IsEnabled = true;
		}

		private void SubmitNewThread(object sender, EventArgs e)
		{
			if (sender is ThreadControl)
			{
				ThreadControl ctrl = sender as ThreadControl;
				UsenetMessage msg = new UsenetMessage();
				msg.Subject = ctrl.NewSubject;
				msg.Body = ctrl.NewBody;
				msg.RootPostId = ctrl.PostRootId;
				msg.ReplyToPostId = ctrl.PostReplyToId;
				App.Client.Usenet_PostMessageCompleted += NewThreadPosted;
				App.Client.Usenet_PostMessageAsync(App.InternalSessionId, SystemId, msg);
			}
		}

		private void NewThreadPosted(object sender, Usenet_PostMessageCompletedEventArgs e)
		{
			App.Client.Usenet_PostMessageCompleted -= NewThreadPosted;
			VisualStateManager.GoToState(this, "Overview", true);
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result)
				Load(SystemId);
			btnNewThread.IsEnabled = true;
		}

		#endregion
	}

	public class FeatureUsenetUiFactory : UiFactoryBase
	{
		public override InterfaceCategory UiCategory
		{
			get { return InterfaceCategory.SystemFeature; }
		}

		public override IProcess CreateProgram()
		{
			return new FeatureUsenetControl();
		}
	}
}